#include "engine.h"
#include "renderhierarchy.h"
#include "rendersystem.h"
#include "core/stringhelper.h"

void renderhierarchy_t::set_world_matrix()
{
	node_buf[0].world_matrix=node_buf[0].local_matrix;
	for (unsigned n=1; n<node_buf.size();++n)
	{
		rendernode_t& act=node_buf[n];
		act.world_matrix.mul(act.local_matrix,node_buf[act.parent_index].world_matrix);
	}
}

void renderhierarchy_t::draw()
{
	set_world_matrix();

	for (unsigned n=1;n<node_buf.size(); ++n)
	{
		rendernode_t& act=node_buf[n];

		if (act.mesh)
		{
			RSYS->set_object_world_matrix(act.world_matrix);
			act.mesh->draw();
		}
	}
}

struct anim_temp_t
{
	float3	m_pos;
	float4  m_rot;
	float3	m_scale;
	uint32	m_valid;
};


anim_temp_t anim_cache[2][1000];
void renderhierarchy_t::set_animation_frame(animation_t* anim0, const float anim0_time, animation_t* anim1/* =NULL */, const float anim1_time/* =0 */, const float blend/* =0 */)
{
	if (animation)
	{

		float anim_time[2] = { anim0_time, anim1_time };
		animation_t* clip[2]={anim0,anim1};
		if (blend>0)
		{
		}
		else
		{
			clip[1]=0;
		}

		if (!clip[0] && !clip[1])
			return;

		memset(&anim_cache[0][0], 0, sizeof(anim_temp_t)*node_buf.size());
		memset(&anim_cache[1][0], 0, sizeof(anim_temp_t)*node_buf.size());

		for (uint32 pass=0;pass<2;pass++)
		{
			if (!clip[pass]) continue;
			float t=max(anim_time[pass]*clip[pass]->timescale, 0.0f);
			uint32 index=(uint32)t;
			float frac=t-(float)index;
			for (uint32 i=0;i<clip[pass]->tracks.size();i++)
			{
				float3 pass_pos;
				float4 pass_rot;
				float3 pass_scale;

				const animtrack_t& track=clip[pass]->tracks[i];
				
				const float3& pos0=track.positions[min(index, track.positions.size()-1)];
				const float3& pos1=track.positions[min(index+1, track.positions.size()-1)];
				anim_cache[pass][track.node_index].m_pos=lerp(pos0, pos1, frac);

				const float4& rot0=track.rotations[min(index, track.rotations.size()-1)];
				const float4& rot1=track.rotations[min(index+1, track.rotations.size()-1)];
				anim_cache[pass][track.node_index].m_rot=slerp(rot0, rot1, frac);

				const float3& scale0=track.scales[min(index, track.scales.size()-1)];
				const float3& scale1=track.scales[min(index+1, track.scales.size()-1)];
				anim_cache[pass][track.node_index].m_scale=lerp(scale0, scale1, frac);

				anim_cache[pass][track.node_index].m_valid=1;
			}
		}

		for (uint32 i=0;i<node_buf.size();i++)
		{
			if (anim_cache[0][i].m_valid && anim_cache[1][i].m_valid)
			{
				node_buf[i].local_matrix.compose( lerp(anim_cache[0][i].m_scale, anim_cache[1][i].m_scale, blend),
					slerp(anim_cache[0][i].m_rot, anim_cache[1][i].m_rot, blend),
					lerp(anim_cache[0][i].m_pos, anim_cache[1][i].m_pos, blend)
					);
			} else
			if (anim_cache[0][i].m_valid)
			{
				node_buf[i].local_matrix.compose(anim_cache[0][i].m_scale, anim_cache[0][i].m_rot, anim_cache[0][i].m_pos);
			} else
			if (anim_cache[1][i].m_valid)
			{
				node_buf[i].local_matrix.compose(anim_cache[1][i].m_scale, anim_cache[1][i].m_rot, anim_cache[1][i].m_pos);
			}
		}
	}
}

#ifdef LEO_DESIGNER
void renderhierarchy_t::save()
{
	file_t f((stringhelper::remove_extension(*name.str)+".leo3d").c_str(),"wb");

	f.write(node_buf.size());
	for (uint32 n=0; n<node_buf.size();++n)
	{
		node_buf[n].save(f);
	}

	f.write(animation!=0);
	if (animation)
		animation->save(f);
}
#endif

void renderhierarchy_t::load()
{
	file_t f((stringhelper::remove_extension(*name.str)+".leo3d").c_str(),"rb");

	uint32 bufsize;
	f.read(bufsize);
	node_buf.resize(bufsize);
	for (uint32 n=0; n<node_buf.size();++n)
	{
		node_buf[n].load(f);
	}

	bool vanim;
	f.read(vanim);
	if (vanim)
	{
		animation=new animationcontainer_t;
		animation->load(f);
	}
	else
	{
		animation=0;
	}
}


